package androidgame.teslawars;

import java.util.List;


import javax.microedition.khronos.opengles.GL10;

import androidgame.framework.Game;
import androidgame.framework.Input.Gesture;
import androidgame.framework.Input.TouchEvent;
import androidgame.framework.gl.Camera2D;
import androidgame.framework.gl.SpriteBatcher;
import androidgame.framework.impl.GLScreen;
import androidgame.framework.math.OverlapTester;
import androidgame.framework.math.Rectangle;
import androidgame.framework.math.Vector2;
import androidgame.teslawars.game.Level;
import androidgame.teslawars.game.Tile;
import androidgame.teslawars.game.Unit;
import androidgame.teslawars.game.Level.Decision;
import androidgame.teslawars.game.Level.GameState;

// @author dicarlo2

public class GameScreen extends GLScreen {
	static final int GAME_READY = 0;
	static final int GAME_RUNNING = 1;
	static final int GAME_OVER = 2;

	int state;
	Camera2D guiCam;
	Camera2D worldCam;
	Vector2 touchPointGUI; // Create with initialization so the garbage
							// collector does not get mad.
	Vector2 touchPointGame;
	SpriteBatcher batcher;
	Level level;
	WorldRenderer renderer;

	Rectangle menuBounds;
	Rectangle mainMenuSelectBounds;
	Rectangle endTurnBounds;
	Rectangle confirmDialogBounds;
	Rectangle cancelDialogBounds;
	Rectangle nextBounds;
	Rectangle endGameBounds;

	boolean renderMenu;
	Vector2 flingVelocity;
	float flingDeltaTime;

	public GameScreen(Game game, Level level) {
		super(game);
		state = GAME_RUNNING;
		guiCam = new Camera2D(glGraphics, 960, 640);
		touchPointGUI = new Vector2();
		touchPointGame = new Vector2();
		batcher = new SpriteBatcher(glGraphics, 1000);
		this.level = level;
		worldCam = new Camera2D(glGraphics, 12, 8);
		worldCam.position.set(level.getCenter());
		renderer = new WorldRenderer(glGraphics, batcher, level, worldCam);
		flingVelocity = new Vector2(0, 0);
		flingDeltaTime = 10;
		renderMenu = false;

		menuBounds = new Rectangle(694, 570, 256, 60);
		mainMenuSelectBounds = new Rectangle(374, 530, 576, 70);
		endTurnBounds = new Rectangle(374, 460, 512, 60);
		confirmDialogBounds = new Rectangle(24, 62, 224, 68);
		cancelDialogBounds = new Rectangle(24, 18, 192, 48);
		nextBounds = new Rectangle(24, 560, 128, 60);
		endGameBounds = new Rectangle(328, 296, 288, 48);
	}

	@Override
	public void update(float deltaTime) {
		if (deltaTime > 0.1f)
			deltaTime = 0.1f;

		switch (state) {
		case GAME_READY:
			updateReady();
			break;
		case GAME_RUNNING:
			updateRunning(deltaTime);
			break;
		case GAME_OVER:
			updateGameOver();
			break;
		}

	}

	// Example code to only start running the game when they touch the screen
	private void updateReady() {
		if (game.getInput().getTouchEvents().size() > 0) {
			state = GAME_RUNNING;
		}
	}

	private void updateRunning(float deltaTime) {			
		List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
		game.getInput().getKeyEvents();
		
		int len = touchEvents.size();
		for (int i = 0; i < len; i++) {
			TouchEvent event = touchEvents.get(i);

			if (event.type == TouchEvent.TOUCH_DOWN) {
				touchPointGUI.set(event.x, event.y);
				guiCam.touchToWorld(touchPointGUI);
				if (updateGUI(touchPointGUI)) // If a change is made to the GUI,
					return; // that means no further change
				// is required from selecting a tile
				touchPointGame.set(event.x, event.y);
				worldCam.touchToWorld(touchPointGame);
				level.update(touchPointGame);
			}
		}
		
		// Gesture support. If a gesture is recognized, the appropriate worldCam change occurs (drag,zoom). If fling is
		// recognized, fling support is enabled via flingDeltaTime.
		List<Gesture> gestures = game.getInput().getGestures();
		len = gestures.size();
		for (int i = 0; i < len; i++) {
			Gesture gesture = gestures.get(i);
			
			if (gesture.type == Gesture.GESTURE_DRAG){
				touchPointGUI.set(gesture.dragDistanceX, gesture.dragDistanceY);
				worldCam.distanceInWorld(touchPointGUI);
				worldCam.position.add(touchPointGUI);
			} else if (gesture.type == Gesture.GESTURE_ZOOM) {
				worldCam.zoom = worldCam.zoom * gesture.zoom;
				if (worldCam.zoom < .65f)
					worldCam.zoom = .65f;
			} else if (gesture.type == Gesture.GESTURE_FLING) {
				flingVelocity.set(gesture.velocityX , gesture.velocityY);
				worldCam.distanceInWorld(flingVelocity);
				if (flingVelocity.x < .25f && flingVelocity.x > .25f && flingVelocity.y < .25f && flingVelocity.y > .25f)
					flingDeltaTime = 10;
				else
					flingDeltaTime = 0;
			}
		}
		
		// Fling gesture support. If a fling gesture is recognized, uses the velocity to continue the screen movement.
		if (flingDeltaTime < .5f) {
			worldCam.position.add(flingVelocity.x * deltaTime, flingVelocity.y * deltaTime);
			if (flingVelocity.x > 0){
				flingVelocity.x -= .2f;
				if (flingVelocity.x < 0)
					flingVelocity.x = 0;
			}
			else if (flingVelocity.x < 0) {
				flingVelocity.x += .2f;
				if (flingVelocity.x > 0)
					flingVelocity.x = 0;
			}
			if (flingVelocity.y > 0){
				flingVelocity.y -= .2f;
				if (flingVelocity.y < 0)
					flingVelocity.y = 0;
			}
			else if (flingVelocity.y < 0) {
				flingVelocity.y += .2f;
				if (flingVelocity.y > 0)
					flingVelocity.y = 0;
			}
			flingDeltaTime += deltaTime;
		}
		
		
		if (level.getState() == GameState.GAME_OVER){
			state = GAME_OVER;
		}

	}

	private boolean updateGUI(Vector2 touchPointGUI) {
		
		// Touching anywhere causes the transition to the next players turn.
		if(level.getState() == GameState.END_TURN)
			level.update(Decision.END_TURN_COMPLETE);
		
		// If NEXT is touched, tells level to find the next unit, and then updates the camera to center on the unit.
		// If nothing is found, the camera does not change.
		if (OverlapTester.pointInRectangle(nextBounds, touchPointGUI)){
			level.update(Decision.NEXT_UNIT);
			if (level.getSelectedUnit() != null){
				worldCam.position.set(level.getSelectedUnit().getX(), level.getSelectedUnit().getY());
				worldCam.zoom = 1;
			}
			return true;
		}

		// activate Menu
		if (OverlapTester.pointInRectangle(menuBounds, touchPointGUI)) {
			renderMenu = true;
			return true;
		} // end code to activate menu

		// Main Menu and End Turn selection logic
		if (renderMenu == true
				&& OverlapTester.pointInRectangle(mainMenuSelectBounds,
						touchPointGUI)) {
			game.setScreen(new MainMenuScreen(game)); // Potentially add a
														// dialog box before
														// this in case of
			return true; // accidental selection
		} else if (renderMenu == true
				&& OverlapTester.pointInRectangle(endTurnBounds, touchPointGUI)) {
			level.update(Decision.END_TURN);
			renderMenu = false;
			return true;
		} else if (renderMenu == true) {
			renderMenu = false;
			return false; // **Experimental. If neither menu item is selected,
							// tile will be selected.
		} // end Menu logic

		// Decision Dialog logic.
		if (level.getState() == GameState.CONFIRM_MOVE
				|| level.getState() == GameState.CONFIRM_ATTACK) {
			if (OverlapTester.pointInRectangle(confirmDialogBounds,
					touchPointGUI)) {
				level.update(Decision.CONFIRM);
				return true;
			} else if (OverlapTester.pointInRectangle(cancelDialogBounds,
					touchPointGUI)) {
				level.update(Decision.CANCEL);
				return true;
			}
		} // end decision dialog logic

		return false;
	}

	private void updateGameOver() {
		List<TouchEvent> touchEvents = game.getInput().getTouchEvents();
		game.getInput().getKeyEvents();
		game.getInput().getGestures();
		
		int len = touchEvents.size();
		for (int i = 0; i < len; i++) {
			TouchEvent event = touchEvents.get(i);

			if (event.type == TouchEvent.TOUCH_DOWN) {
				touchPointGUI.set(event.x, event.y);
				guiCam.touchToWorld(touchPointGUI);
				if (OverlapTester.pointInRectangle(endGameBounds, touchPointGUI)){
					game.setScreen(new MainMenuScreen(game));
					return;
				}
			} 
		}

	}

	@Override
	public void present(float deltaTime) {
		GL10 gl = glGraphics.getGL();
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
		gl.glEnable(GL10.GL_TEXTURE_2D);

		renderer.render();

		guiCam.setViewportAndMatrices();
		gl.glEnable(GL10.GL_BLEND);
		gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		batcher.beginBatch(Assets.items);
		if (state == GAME_OVER) {
			if (level.getPlayer1UnitList().size() == 0)
				Assets.teslaWarsFont.drawText(batcher, "PLAYER 2 WINS!", 48, 600, 64, 60);
			else
				Assets.teslaWarsFont.drawText(batcher, "PLAYER 1 WINS!", 48, 600, 64, 60);
			Assets.readableFont.drawText(batcher, "MAIN MENU", 344, 320, 36, 48);
			batcher.endBatch();
			gl.glDisable(GL10.GL_BLEND);
			return;
		} // If the state is game over, nothing else should be drawn.
		Assets.teslaWarsFont.drawText(batcher, "MENU", 726, 600, 64, 60);
		Assets.readableFont.drawText(batcher, "NEXT", 40, 600, 36, 48);
		if (renderMenu == true) {
			Assets.teslaWarsFont.drawText(batcher, "MAIN MENU", 406, 560, 64, 60);
			Assets.teslaWarsFont.drawText(batcher, "END TURN", 406, 500, 64, 60);
		}
		if (level.getState() == GameState.CONFIRM_MOVE) {
			batcher.drawSprite(144, 92, 264, 180, Assets.dialog);
			Assets.readableFont.drawText(batcher, "MOVE?", 40, 150, 36, 48);
			Assets.readableFont.drawText(batcher, "CONFIRM", 40, 96, 36, 48);
			Assets.readableFont.drawText(batcher, "CANCEL", 40, 42, 36, 48);
		}
		if (level.getState() == GameState.CONFIRM_ATTACK) {
			batcher.drawSprite(144, 92, 264, 180, Assets.dialog);
			Assets.readableFont.drawText(batcher, "ATTACK?", 40, 150, 36, 48);
			Assets.readableFont.drawText(batcher, "CONFIRM", 40, 96, 36, 48);
			Assets.readableFont.drawText(batcher, "CANCEL", 40, 42, 36, 48);
		}
		if (level.getState() == GameState.END_TURN){
			switch (level.getPlayerTurn()){
			case PLAYER1:
				Assets.teslaWarsFont.drawText(batcher, "PLAYER 1", 256, 320, 64, 60);
				break;
			case PLAYER2:
				Assets.teslaWarsFont.drawText(batcher, "PLAYER 2", 256, 320, 64, 60);
				break;
			}			
		}
		if (level.getSelectedTile() != null)
			if (level.getSelectedTile().getUnit() != null)
				drawStatsScreen(level.getSelectedTile(), level.getSelectedTile().getUnit());
			else
				drawStatsScreen(level.getSelectedTile(), null);
		batcher.endBatch();
		gl.glDisable(GL10.GL_BLEND);

	}

	public void drawStatsScreen(Tile tile, Unit unit) {

		// Terrain stats screen drawing
		batcher.drawSprite(840, 105, 220, 190, Assets.dialog);
		switch (tile.getTerrain()) {
		case MOUNTAIN:
			batcher.drawSprite(840, 148, 64, 64, Assets.mountain);
			break;
		case FOREST:
			batcher.drawSprite(840, 148, 64, 64, Assets.twoTrees);
			break;
		case PLAIN:
			batcher.drawSprite(840, 148, 64, 64, Assets.grass1);
			break;
		}
		Assets.readableFont.drawText(batcher, "DEFENSE:" + tile.getDefenseRating(), 760,
				99.832f, 20, 25);
		
		// Unit stats screen drawing
		if (unit != null) {
			batcher.drawSprite(610, 105, 220, 190, Assets.dialog);
			if (level.getPlayer1UnitList().contains(unit)) {
				switch (unit.getUnitName()){
					case TANK:
						batcher.drawSprite(610, 148, 64, 64, Assets.player1Tank);
						break;
					case JET:
						batcher.drawSprite(610, 148, 64, 64, Assets.player1Jet);
						break;
					case FOOTSOLDIER:
						batcher.drawSprite(610, 148, 64, 64, Assets.player1Soldier);
						break;
				}
			}
			
			if(level.getPlayer2UnitList().contains(unit)) {
				switch (unit.getUnitName()) {
				case TANK:
					batcher.drawSprite(610, 148, 64, 64, Assets.player2Tank);
					break;
				case JET:
					batcher.drawSprite(610, 148, 64, 64, Assets.player2Jet);
					break;
				case FOOTSOLDIER:
					batcher.drawSprite(610, 148, 64, 64, Assets.player2Soldier);
					break;
				}
			}
			Assets.readableFont.drawText(batcher, "ATTACK:" + unit.getAttackDamage(),
					530, 99.832f, 20, 25);
			Assets.readableFont.drawText(batcher, "RANGE: " + unit.getAttackRange(), 530,
					71.706f, 20, 25);
			Assets.readableFont.drawText(batcher, "ARMOR: " + unit.getArmor(), 530,
					42.5f, 20, 25);
		}
	}

	@Override
	public void pause() {
		Settings.save(game.getFileIO());
	}

	@Override
	public void resume() {
	}

	@Override
	public void dispose() {
	}

}
